package models;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.Page;
import play.data.validation.Constraints;
import play.db.ebean.Model;

/**
 * Modele de la classe Question.
 * 
 * @author ProjetSI-QCM
 * 
 */
@SuppressWarnings("serial")
@Entity
public class Question extends Model {
    /**
     * Identifiant de la question.
     */
    @Id
    private Long idQuestion;
    /**
     * Référence vers le NiveauQuestion.
     */
    private NiveauQuestion niveauQuestion;
    /**
     * Référence vers le chapitre associé à la question.
     */
    private Chapitre chapitre;

    /**
     * Liste des choix possibles pour cette question.
     */
    private List<Choix> listeChoix = new ArrayList<Choix>();;

    /**
     * Libelle de la question.
     */
    @Constraints.Required
    private String libelleQuestion;
    /**
     * Commentaire sur la question(facultatif).
     */
    private String commentaire;

    /**
     * Finder la classe Question.
     */
    private static Finder<Long, Question> find = new Finder<Long, Question>(
            Long.class, Question.class);

    /**
     * Recupere une Question à partir de son identifiant.
     * 
     * @param id
     *            L'identifiant de la question
     * @return Question L'objet récupéré
     */
    public static Question findById(final Long id) {
        return Ebean.find(Question.class, id);
    }
    
    /**
     * Permet de récupérer la Liste de toutes les questions créées.
     * 
     * @return List<Question> La liste des Questions créées.
     */
    public static List<Question> findAll() {
        return find.all();
    }

    /**
     * Liste des options pour les listes déroulantes.
     * 
     * @return Map<String,String>
     */
    public static Map<String, String> options() {
        final LinkedHashMap<String, String> options = 
                new LinkedHashMap<String, String>();
        for (Question c : Question.find.orderBy("libelleQuestion").findList()) {
            options.put(c.getIdQuestion().toString(), c.getLibelleQuestion()
                    .toString());
        }
        return options;
    }

    /**
     * Retourne la liste des questions pour un theme.
     * 
     * @param idTheme
     *            l'identifiant du theme
     * @return liste des questions associées a un theme
     */
    public static List<Question> findFromTheme(final Long idTheme) {
        Collection<Matiere> lMatieres;
        final Collection<Chapitre> lChapitres = new ArrayList<Chapitre>();
        final Collection<Question> lQuestions = new ArrayList<Question>();

        lMatieres = Theme.findById(idTheme).getSesMatieres();

        for (Matiere matiere : lMatieres) {
            lChapitres.addAll(matiere.getSesChapitres());
        }

        for (Chapitre chapitre : lChapitres) {
            lQuestions.addAll(chapitre.getSesQuestions());
        }

        return (List<Question>) lQuestions;
    }

    /**
     * Retourne la liste des questions pour une matiere.
     * 
     * @param idMatiere
     *            l'identifiant de la matiere
     * @return liste des questions associées a une matiere
     */
    public static List<Question> findFromMatiere(final Long idMatiere) {
        Collection<Chapitre> lChapitres;
        final Collection<Question> lQuestions = new ArrayList<Question>();

        lChapitres = Matiere.findById(idMatiere).getSesChapitres();

        for (Chapitre chapitre : lChapitres) {
            lQuestions.addAll(chapitre.getSesQuestions());
        }

        return (List<Question>) lQuestions;
    }

    /**
     * Retourne la liste des questions pour un chapitre.
     * 
     * @param idChapitre
     *            l'identifiant du chapitre
     * @return liste des questions associées a un chapitre
     */
    public static List<Question> findFromChapitre(final Long idChapitre) {
        return (List<Question>) Chapitre.findById(idChapitre).getSesQuestions();
    }

    /**
     * Retourne la liste des questions pour un niveau.
     * 
     * @param nq
     *            le niveau
     * @return liste des questions associées a un niveau
     */
    public static List<Question> findByNiveauQuestion(final NiveauQuestion nq) {
    		return find.where().eq("niveauQuestion", nq).findList();
    }
    
    
	/**
	 * Supprimer une question de la base de données.
	 * 
	 * @param id
	 *            l'identifiant de l'objet à supprimer.
	 */
	public static void delete(final Long id) {
		Question q = Question.findById(id);
		for (Qcm qcm : Qcm.findAll()) {
			if (qcm.getListeQuestions().contains(q)) {
				qcm.getListeQuestions().remove(q);
				Qcm.update(qcm);
			}
		}
		for (Choix choix : q.getListeChoix()) {
			Choix.delete(choix.getIdChoix());
		}
		find.ref(id).delete();
	}

    /**
     * Permet de sauvegarder un objet en base de Données.
     * 
     * @param question
     *            La question à sauvegarder
     */
    public static void create(final Question question) {
        Ebean.save(question);
    }

    /**
     * Permet de modifier un objet en base de données.
     * 
     * @param question
     *            La question à modifier.
     */
    public static void update(final Question question) {
        Ebean.update(question);
    }

    /**
     * Retourne une Page de Question.
     * 
     * @param page
     *            Page à afficher
     * @param pageSize
     *            Nombre d'objets par page
     * @param sortBy
     *            Propriété utilisée pour le tri
     * @param order
     *            Sens du tri (asc ou desc)
     * @param filter
     *            Filtre appliqué sur le nom de la colonne
     * @return Page<question> la page
     */
    public static Page<Question> page(final int page, final int pageSize,
            final String sortBy, final String order, final String filter) {
        return find.where().ilike("idQuestion", "%" + filter + "%")
                .orderBy(sortBy + " " + order).fetch("chapitre")
                .findPagingList(pageSize).setFetchAhead(false).getPage(page);
    }

	/**
	 * @return the idQuestion
	 */
	public final Long getIdQuestion() {
		return idQuestion;
	}

	/**
	 * @param id the idQuestion to set
	 */
	public final void setIdQuestion(final Long id) {
		this.idQuestion = id;
	}

	/**
	 * @return the niveauQuestion
	 */
	@ManyToOne
	public final NiveauQuestion getNiveauQuestion() {
		return niveauQuestion;
	}

	/**
	 * @param nq the niveauQuestion to set
	 */
	public final void setNiveauQuestion(final NiveauQuestion nq) {
		this.niveauQuestion = nq;
	}

	/**
	 * @return the chapitre
	 */
	@ManyToOne
	public final Chapitre getChapitre() {
		return chapitre;
	}

	/**
	 * @param c the chapitre to set
	 */
	public final void setChapitre(final Chapitre c) {
		this.chapitre = c;
	}

	/**
	 * @return the listeChoix
	 */
	@OneToMany(mappedBy = "question", cascade = CascadeType.ALL)
	public final List<Choix> getListeChoix() {
		return listeChoix;
	}

	/**
	 * @param l the listeChoix to set
	 */
	public final void setListeChoix(final List<Choix> l) {
		this.listeChoix = l;
	}

	/**
	 * @return the libelleQuestion
	 */
	public final String getLibelleQuestion() {
		return libelleQuestion;
	}

	/**
	 * @param l the libelleQuestion to set
	 */
	public final void setLibelleQuestion(final String l) {
		this.libelleQuestion = l;
	}

	/**
	 * @return the commentaire
	 */
	public final String getCommentaire() {
		return commentaire;
	}

	/**
	 * @param c the commentaire to set
	 */
	public final void setCommentaire(final String c) {
		this.commentaire = c;
	}

}
